#if UNITY_STANDALONE || UNITY_ANDROID || UNITY_IOS || UNITY_WSA || UNITY_WEBGL
using UnityEngine;
using UnityEngine.EventSystems;

public static class UnityExtensions
{
    /// <summary>
    /// 将给定方向向量转换为相对于指定变换（通常是摄像机）的方向。
    /// </summary>
    /// <param name="cameraTarget">目标变换，通常是摄像机的变换。</param>
    /// <param name="direction">要转换的方向向量。</param>
    /// <returns>转换后的方向向量。</returns>
    public static Vector3 Transform3Dir(this Transform cameraTarget, Vector3 direction)
    {
        var f = Mathf.Deg2Rad * (-cameraTarget.rotation.eulerAngles.y);
        direction.Normalize();
        var ret = new Vector3(direction.x * Mathf.Cos(f) - direction.z * Mathf.Sin(f), 0, direction.x * Mathf.Sin(f) + direction.z * Mathf.Cos(f));
        return ret;
    }

    /// <summary>
    /// 将给定方向向量转换为相对于指定变换（通常是摄像机）的方向。
    /// </summary>
    /// <param name="cameraTarget">目标变换，通常是摄像机的变换。</param>
    /// <returns>转换后的方向向量。</returns>
    public static Vector3 Transform3Dir(this Transform cameraTarget) => Transform3Dir(cameraTarget, InputEx.Direction);

    /// <summary>
    /// 对指定的变换进行线性插值旋转，朝向给定的方向。
    /// </summary>
    /// <param name="transform">要旋转的变换。</param>
    /// <param name="direction">目标方向向量。</param>
    /// <param name="t">插值因子，范围通常在0到1之间，默认值为0.5。</param>
    public static void LerpRotation(this Transform transform, Vector3 direction, float t = 0.5f)
    {
        transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(direction, Vector3.up), t);
    }

    /// <summary>
    /// 向量相乘
    /// </summary>
    /// <param name="self"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public static Vector3 Multiply(this Vector3 self, Vector3 value)
    {
        return new Vector3(self.x * value.x, self.y * value.y, self.z * value.z);
    }

    public static Vector2 PointToAxis(this Rect rectangle, Vector2 point)
    {
        var normalized = Rect.PointToNormalized(rectangle, point);
        var axis = new Vector2(normalized.x * 2f - 1f, normalized.y * 2f - 1f);
        return axis;
    }
}

public static class InputEx
{
    /// <summary>
    /// 获取当前的方向向量，基于用户的输入。
    /// </summary>
    /// <remarks>
    /// 方向向量的x分量来自“Horizontal”输入，y分量为0，z分量来自“Vertical”输入。
    /// </remarks>
    public static Vector3 Direction => new(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));

    /// <summary>
    /// 获取当前的方向向量，基于用户的输入。
    /// </summary>
    /// <remarks>
    /// 方向向量的x分量来自“Horizontal”输入，y分量来自“Vertical”输入，z分量为0。
    /// </remarks>
    public static Vector3 Direction3D => new(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"), 0);

    /// <summary>
    /// 获取当前的方向向量，基于用户的输入。
    /// </summary>
    /// <remarks>
    /// 方向向量的x分量来自“Horizontal”输入，y分量来自“Vertical”输入。
    /// </remarks>
    public static Vector2 Direction2D => new(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
}

public static class UIDragHandlerEx
{
    /// <summary>
    /// 获取拖动偏移，这是在OnBeginDrag事件获取偏移并且保存起来
    /// </summary>
    /// <param name="self"></param>
    /// <param name="screenRt">面板的矩形</param>
    /// <param name="eventData">事件数据</param>
    /// <returns></returns>
    public static Vector2 GetDragOffset(this RectTransform self, RectTransform screenRt, PointerEventData eventData)
    {
        Vector2 dragOffset = default;
        if (RectTransformUtility.ScreenPointToLocalPointInRectangle(screenRt, eventData.position, eventData.pressEventCamera, out Vector2 localPoint))
            dragOffset = self.anchoredPosition - localPoint;
        return dragOffset;
    }

    /// <summary>
    /// 获取拖动偏移，这是在OnBeginDrag事件获取偏移并且保存起来
    /// </summary>
    /// <param name="self"></param>
    /// <param name="screenRt">面板的矩形</param>
    /// <param name="eventData">事件数据</param>
    /// <returns></returns>
    public static void GetDragOffset(this RectTransform self, RectTransform screenRt, PointerEventData eventData, out Vector2 dragOffset)
    {
        RectTransformUtility.ScreenPointToLocalPointInRectangle(screenRt, eventData.position, eventData.pressEventCamera, out Vector2 localPoint);
        dragOffset = self.anchoredPosition - localPoint;
    }

    /// <summary>
    /// 拖动UI，这里在OnDrag方法使用
    /// </summary>
    /// <param name="self"></param>
    /// <param name="screenRt">面板的矩形</param>
    /// <param name="eventData">事件数据</param>
    /// <param name="dragOffset">拖动偏移量</param>
    public static void DragUI(this RectTransform self, RectTransform screenRt, PointerEventData eventData, Vector2 dragOffset)
    {
        if (RectTransformUtility.ScreenPointToLocalPointInRectangle(screenRt, eventData.position, eventData.pressEventCamera, out Vector2 localPoint))
            self.anchoredPosition = localPoint + dragOffset;
    }

    /// <summary>
    /// 拖动UI，这里在OnDrag方法使用
    /// </summary>
    /// <param name="self"></param>
    /// <param name="screenRt">屏幕的矩形</param>
    /// <param name="eventData">事件数据</param>
    /// <param name="dragOffset">拖动偏移量</param>
    /// <param name="screenSize">屏幕大小</param>
    public static void DragUILimit(this RectTransform self, RectTransform screenRt, PointerEventData eventData, Vector2 dragOffset)
    {
        var parentSize = screenRt.rect.size;
        var elementSize = self.rect.size;

        var anchorCenter = new Vector2(
            (self.anchorMin.x + self.anchorMax.x) * 0.5f * parentSize.x,
            (self.anchorMin.y + self.anchorMax.y) * 0.5f * parentSize.y
        );

        var anchorSizeEffect = new Vector2(
            (self.anchorMax.x - self.anchorMin.x) * parentSize.x,
            (self.anchorMax.y - self.anchorMin.y) * parentSize.y
        );

        var effectiveSize = new Vector2(
            Mathf.Min(elementSize.x, anchorSizeEffect.x > 0 ? anchorSizeEffect.x : elementSize.x),
            Mathf.Min(elementSize.y, anchorSizeEffect.y > 0 ? anchorSizeEffect.y : elementSize.y)
        );

        var minBound = new Vector2(
            parentSize.x / 2f + effectiveSize.x * 0.5f - anchorCenter.x,
            parentSize.y / 2f + effectiveSize.y * 0.5f - anchorCenter.y
        );
        var maxBound = new Vector2(
            parentSize.x / 2f + parentSize.x - effectiveSize.x * 0.5f - anchorCenter.x,
            parentSize.y / 2f + parentSize.y - effectiveSize.y * 0.5f - anchorCenter.y
        );

        var clampedPos = new Vector2(
            Mathf.Clamp(eventData.position.x + dragOffset.x, minBound.x, maxBound.x),
            Mathf.Clamp(eventData.position.y + dragOffset.y, minBound.y, maxBound.y)
        );

        if (RectTransformUtility.ScreenPointToLocalPointInRectangle(screenRt, clampedPos, eventData.pressEventCamera, out Vector2 localPos))
        {
            self.anchoredPosition = localPos;
        }
    }

    /// <summary>
    /// 拖动UI在Update，可在Update进行调用
    /// </summary>
    /// <param name="self"></param>
    /// <param name="screenRt">面板的矩形</param>
    /// <param name="uiCamera">UI相机</param>
    /// <param name="dragOffset">拖动偏移量</param>
    public static void UpdateDragUI(this RectTransform self, RectTransform screenRt, Camera uiCamera, Vector2 dragOffset)
    {
        var mousePosition = Input.mousePosition;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(screenRt, mousePosition, uiCamera, out Vector2 localPoint);
        self.anchoredPosition = localPoint + dragOffset;
    }

    /// <summary>
    /// 设置拖动阈值, 提高拖动灵敏度
    /// 由于Unity的事件系统有一个默认的拖动阈值（通常是 5 像素），只有当鼠标移动超过这个阈值时，OnDrag 才会被调用。为了解决这个问题，你可以通过自定义一个拖动处理来实现更灵敏的响应。
    /// </summary>
    /// <param name="self"></param>
    public static void DragThreshold(int dragThreshold = 1)
    {
        EventSystem.current.pixelDragThreshold = dragThreshold;
    }

    /// <summary>
    /// 获取屏幕位置偏移, 获取鼠标点击的位置和图像自身矩形的位置偏移
    /// </summary>
    /// <param name="self"></param>
    /// <param name="eventData">事件数据</param>
    /// <returns></returns>
    public static Vector2 GetScreenPositionOffset(this RectTransform self, RectTransform screenRt, PointerEventData eventData)
    {
        var screenPosition = RectTransformUtility.WorldToScreenPoint(eventData.pressEventCamera, self.position);
        RectTransformUtility.ScreenPointToLocalPointInRectangle(screenRt, eventData.position, eventData.pressEventCamera, out Vector2 mouseLocalPoint);
        RectTransformUtility.ScreenPointToLocalPointInRectangle(screenRt, screenPosition, eventData.pressEventCamera, out Vector2 thisLocalPoint);
        return thisLocalPoint - mouseLocalPoint;
    }
}

public static class RectTransformEx
{
    /// <summary>
    /// 设置UI元素在屏幕空间中的位置（简化版）
    /// </summary>
    /// <param name="self">目标RectTransform组件</param>
    /// <param name="screenPoint">目标屏幕坐标点（像素坐标）</param>
    public static void SetScreenPoint(this RectTransform self, Vector2 screenPoint)
    {
        var canvas = self.GetComponentInParent<Canvas>();
        var canvasRectTransform = (RectTransform)canvas.transform;
        var uiCamera = canvas.worldCamera;
        SetScreenPoint(self, canvasRectTransform, uiCamera, screenPoint);
    }

    /// <summary>
    /// 设置UI元素在屏幕空间中的位置（完整版）
    /// </summary>
    /// <param name="self">目标RectTransform组件</param>
    /// <param name="canvasRectTransform">所属Canvas的RectTransform</param>
    /// <param name="uiCamera">渲染UI的相机（Screen Space Camera模式时使用）</param>
    /// <param name="screenPoint">目标屏幕坐标点（像素坐标）</param>
    public static void SetScreenPoint(this RectTransform self, RectTransform canvasRectTransform, Camera uiCamera, Vector2 screenPoint)
    {
        var scaleFactor = canvasRectTransform.lossyScale.x;
        var pivotOffset = self.rect.size * self.pivot * scaleFactor;
        RectTransformUtility.ScreenPointToWorldPointInRectangle(canvasRectTransform, screenPoint, uiCamera, out Vector3 worldPos);
        self.position = worldPos + (Vector3)pivotOffset;
    }
}
#endif